/**
 * Module is the version container of a specific Play! framework module.
 * 
 * 
 * @author Eric LEON
 * @version 1.0.0
 */
package models;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;

import play.db.jpa.Model;

import com.google.gson.annotations.Expose;

@Entity(name="tdModule")
public class Module extends Model {

	/**
	 * The module name, can't be null and must be unique.
	 */
	@Column(nullable=false,unique=true)
	@Expose
    public String name = null;
	
	/**
	 * The module full description string.
	 */
	@Expose
	@Column(nullable=false)
    public String fullname = null;
    
	/**
	 * The module versions set.
	 */
    @OneToMany(cascade=javax.persistence.CascadeType.ALL, fetch=FetchType.LAZY, orphanRemoval=true)
    @OrderBy("version asc")
	@Expose
    public Set<Version> versions = new HashSet<Version>();
    
	/**
	 * The module license type.
	 */
	@Enumerated(EnumType.STRING)
    public LicenseType license = LicenseType.APACHE;
	
    public Module(String name, String fullname, LicenseType license) throws Exception {
    	if (null == name) {
    		throw new Exception("Name should not be null");
    	}
        this.name = name;
        this.fullname = fullname;
        this.license = license;
    }

    public Module() {
    }
    
	@Override
	public String toString() {
		return this.name.toString();
	}
    
	/**
	 * Lists all created modules, ordered by ascending name.
	 * @return	The list.
	 */
    public static List<Module> list() {
    	return Module.find("order by name asc").fetch();
    }
	
    /**
     * Adds a new version for the given module. The version must be unique for a given module. 
     * @param version		The version object.
     * @throws Exception	Thrown when version object already exists for this module.
     */
	public void addVersion(Version version) throws Exception {
		Version v = getVersion(version.version); 
		if (v == null) {
			// Add a new version
			versions.add(version);
		} else if (version.version.equals("head")) {
			// Update head version
			v.matches = version.matches;
			v.code = version.code;
		} else {
			// Version already created
			throw new Exception("Version should be unique");
		}
		save();
	}

	/**
	 * Deletes the given version from this module.
	 * @param version	The version name.
	 * @throws Exception	Thrown when no version match the given name.
	 */
	public void deleteVersion(String version) throws Exception {
		Version v = getVersion(version);
		if (v == null) {
    		throw new Exception("Version not found");
		}
		this.versions.remove(v);
		save();
	}   

	/**
	 * Change module default version. There can be only one default version for a given object.
	 * @param version	The version name that must become the default one.
	 */
	public void defaultVersion(String version) {
		for (Version v:versions) {
			v.isDefault = v.version.equals(version);
		}
		save();
	}   	
	
	/**
	 * Gets the version object corresponding to the given name.
	 * @param version	The version name.
	 * @return	The version object matching the given name, or null if no version found.
	 */
	public Version getVersion(String version) {
		for (Version v:versions) {
			if (v.version.equals(version)) {
				return v;
			}
		}
		return null;
	}

	/**
	 * Gets the default version object for this module.
	 * @return	The version object.
	 */
	public List<Version> getDefaultVersion() {
		
    	StringBuilder request = new StringBuilder();
    	List<Version> lst = null;
    	
    	// Build the SQL request
    	request.append("SELECT v FROM models.Module m, models.Version v")
    			.append(" WHERE m.id=?")
    			.append(" AND v IN ELEMENTS(m.versions)")
    			.append(" AND v.isDefault IS true")
    			.append(" ORDER BY v.name ASC");
		
    	lst = Module.find(request.toString(), this.id).fetch();
    	return lst;
	}
	
}
